﻿using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Timers;
using System.Windows;
using Saber.Core;
using Saber.Core.Plugin;
using Saber.Core.Resource;
using Saber.Helper;
using Saber.Infrastructure;
using Saber.Infrastructure.Http;
using Saber.Infrastructure.Image;
using Saber.Infrastructure.Logger;
using Saber.Infrastructure.UserSettings;
using Saber.ViewModel;
using Stopwatch = Saber.Infrastructure.Stopwatch;

namespace Saber
{
    public partial class App : IDisposable, ISingleInstanceApp
    {
        ////调用API
        //[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, ExactSpelling = true)]
        //public static extern IntPtr GetForegroundWindow(); //获得本窗体的句柄
        //[System.Runtime.InteropServices.DllImport("user32.dll", EntryPoint = "SetForegroundWindow")]
        //public static extern bool SetForegroundWindow(IntPtr hWnd);//设置此窗体为活动窗体
        //定义变量,句柄类型
        //public static IntPtr hWnd;


        public static PublicAPIInstance API { get; private set; }
        private const string Unique = "Saber_Unique_Application_Mutex";
        private static bool _disposed;
        private Settings _settings;
        private MainViewModel _mainVM;
        private SettingWindowViewModel _settingsVM;

        [STAThread]
        public static void Main()
        {
            if (SingleInstance<App>.InitializeAsFirstInstance(Unique))
            {
                using (var application = new App())
                {
                    application.InitializeComponent();
                    application.Run();
                }
            }
        }

        private void OnStartup(object sender, StartupEventArgs e)
        {
            Stopwatch.Normal("|App.OnStartup|Startup cost", () =>
            {
                Log.Info("|App.OnStartup|Begin Saber startup ----------------------------------------------------");
                var info = $"\nSaber version: {Constant.Version}" +
                       $"\nOS Version: {Environment.OSVersion.VersionString}" +
                       $"\nIntPtr Length: {IntPtr.Size}" +
                       $"\nx64: {Environment.Is64BitOperatingSystem}";
                Log.Info($"|App.OnStartup|Runtime info:{info}");
                RegisterAppDomainExceptions();
                RegisterDispatcherUnhandledException();

                ImageLoader.Initialize();
                Alphabet.Initialize();

                _settingsVM = new SettingWindowViewModel();
                _settings = _settingsVM.Settings;

                PluginManager.LoadPlugins(_settings.PluginSettings);
                _mainVM = new MainViewModel(_settings);
                var window = new MainWindow(_settings, _mainVM);
                API = new PublicAPIInstance(_settingsVM, _mainVM);
                PluginManager.InitializePlugins(API);

                Current.MainWindow = window;
                Current.MainWindow.Title = Constant.Saber;

                // happlebao todo temp fix for instance code logic
                // load plugin before change language, because plugin language also needs be changed
                //InternationalizationManager.Instance.Settings = _settings;
                //InternationalizationManager.Instance.ChangeLanguage(_settings.Language);
                // main windows needs initialized before theme change because of blur settigns
                ThemeManager.Instance.Settings = _settings;
                ThemeManager.Instance.ChangeTheme(_settings.Theme);

                Http.Proxy = _settings.Proxy;

                RegisterExitEvents();

                AutoStartup();
                AutoUpdates();

                _mainVM.MainWindowVisibility = _settings.HideOnStartup ? Visibility.Hidden : Visibility.Visible;
                
                Log.Info("|App.OnStartup|End Saber startup ----------------------------------------------------  ");
            });
        }


        private void AutoStartup()
        {
            if (_settings.StartSaberOnSystemStartup)
            {
                if (!SettingWindow.StartupSet())
                {
                    SettingWindow.SetStartup();
                }
            }
        }

        [Conditional("RELEASE")]
        private void AutoUpdates()
        {
            //Task.Run(async () =>
            //{
            //    if (_settings.AutoUpdates)
            //    {
            //        // check udpate every 5 hours
            //        var timer = new Timer(1000 * 60 * 60 * 5);
            //        timer.Elapsed += async (s, e) =>
            //        {
            //            await Updater.UpdateApp();
            //        };
            //        timer.Start();

            //        // check updates on startup
            //        await Updater.UpdateApp();
            //    }
            //});
        }

        private void RegisterExitEvents()
        {
            AppDomain.CurrentDomain.ProcessExit += (s, e) => Dispose();
            Current.Exit += (s, e) => Dispose();
            Current.SessionEnding += (s, e) => Dispose();
        }

        /// <summary>
        /// let exception throw as normal is better for Debug
        /// </summary>
        [Conditional("RELEASE")]
        private void RegisterDispatcherUnhandledException()
        {
            DispatcherUnhandledException += ErrorReporting.DispatcherUnhandledException;
        }


        /// <summary>
        /// let exception throw as normal is better for Debug
        /// </summary>
        [Conditional("RELEASE")]
        private static void RegisterAppDomainExceptions()
        {
            AppDomain.CurrentDomain.UnhandledException += ErrorReporting.UnhandledExceptionHandle;
            AppDomain.CurrentDomain.FirstChanceException += (_, e) =>
            {
                Log.Exception("|App.RegisterAppDomainExceptions|First Chance Exception:", e.Exception);
            };
        }

        public void Dispose()
        {
            // if sessionending is called, exit proverbially be called when log off / shutdown
            // but if sessionending is not called, exit won't be called when log off / shutdown
            if (!_disposed)
            {
                _mainVM.Save();
                _settingsVM.Save();

                PluginManager.Save();
                ImageLoader.Save();
                Alphabet.Save();

                _disposed = true;
            }
        }

        public void OnSecondAppStarted()
        {
            // Current.MainWindow.Visibility = Visibility.Visible;
            _mainVM.MainWindowVisibility = Visibility.Visible;
        }
    }
}